package com.thinkgem.jeesite.common;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.support.SubjectThreadState;
import org.apache.shiro.util.ThreadState;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;
import org.junit.After;
import org.junit.Assert;
import org.junit.runner.RunWith;

import com.thinkgem.jeesite.modules.sys.security.UsernamePasswordToken;

/**
 *TODO:安全测试基类
 *@author 作者：lgx
 *@date 创建时间：2016年3月21日
 *@version V1.0
 */
@ContextConfiguration(locations = { "classpath:spring-context.xml",
		"classpath:spring-context-activiti.xml",
		"classpath:spring-context-shiro.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
// 如果是true不会改变数据库数据，如果是false会改变数据
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public abstract class AbstractServiceTestWithShiro extends AbstractServiceTests {

	private static ThreadState subjectThreadState;

	@Autowired
	private DefaultSecurityManager securityManager;

	protected void login(String userName, String password) {
		Assert.assertTrue("userName can not be empty or null.",
				!StringUtils.isAnyEmpty(userName));
		Assert.assertTrue("password can not be empty or null.",
				!StringUtils.isAnyEmpty(password));
		setSecurityManager(securityManager);
		Subject subject = SecurityUtils.getSubject();
		subject.login(new UsernamePasswordToken(userName, password
				.toCharArray(), false, null, null, false));
	}

	private void setSubject(Subject subject) {
		doClearSubject();
		createThreadState(subject).bind();
	}

	private Subject getSubject() {
		return SecurityUtils.getSubject();
	}

	private ThreadState createThreadState(Subject subject) {
		return new SubjectThreadState(subject);
	}

	private static void setSecurityManager(SecurityManager securityManager) {
		SecurityUtils.setSecurityManager(securityManager);
	}

	private SecurityManager getSecurityManager() {
		return SecurityUtils.getSecurityManager();
	}

	private void doClearSubject() {
		if (subjectThreadState != null) {
			subjectThreadState.clear();
			subjectThreadState = null;
		}
	}

	@After
	public void tearDown() {
		SecurityUtils.getSubject().logout();
	}
}
